home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995…tember: Reference Library / Dev.CD Sep 95 RL / Dev.CD Sep 95 RL.toast / mac / Technical Documentation / develop / develop Issue 15 code / Symmetry & Tiles / Tiler Code / Tilings.c < prev   
Encoding:
C/C++ Source or Header  |  1994-05-27  |  13.0 KB  |  661 lines  |  [TEXT/KAHL]

  1. #include     <graphics libraries.h>
  2. #include     <graphics toolbox.h>
  3. #include     <qd library.h>
  4. #include     <offscreen library.h>
  5. #include    "TileConstants.h"
  6. #include    "TileProtos.h"
  7.  
  8. #include     "Group1.h"
  9. #include     "Group2.h"
  10.  
  11. //---------------------------------------
  12. //    Tile globals
  13. gxPoint            gOrigin = {ff(0), ff(0)};
  14. gxColorSet        gColors;
  15. offscreen        gOffScreen;
  16. gxShape            gTileShape,    // The unit cell (transforms of gDragger contours)
  17.                 gGridShape,    // A rect filled with the pattern
  18.                 gBGShape;    // A rect filled with the background color
  19.  
  20. gxShape            gOpShapes[kNumOpShapes];    // Group of shapes to show the symmetry 
  21.                                             // operations
  22.  
  23. dragger            gDragger;    // A record containing a manipulable contour & associated stuff
  24. gxPatternRecord    gPattern;
  25.  
  26. Boolean            gContRedraw = false, gKeepClosed = true; // State Booleans
  27. long            gSymmetry = p1; // The currently chosen symmetry group
  28. gxViewPort        gViewPort;
  29.  
  30. // ========= Prototypes ==========================================
  31.  
  32. // Prototype of a function in utils.c we use
  33. long     labs(long i);
  34.  
  35. // Prototypes for routines private to this file
  36. long     AddEdgePoint(gxPoint *clickPt, long prevIndex);
  37. Boolean    RemoveEdgePoint(long index);
  38. Boolean IsConstrainedPoint(long ptIndex);
  39.  
  40. void     RemakeOpShapes(Boolean useDefaults, long newSymmetry);
  41.  
  42. void    TrackDraggerPoint(long dragPtIndex, gxPoint *startPt);
  43. Boolean OpHit(gxPoint *clickPt);
  44.  
  45. void     DrawDraggable(void);
  46. void     EraseDraggable(void);
  47. void    DrawOpShapes(void);
  48.  
  49. void     SetLinePoints(gxShape theLine, gxPoint *start, gxPoint *end);
  50.  
  51. //===================================================================
  52.  
  53. // Adds a point to the global snake
  54. long AddEdgePoint(gxPoint *clickPt, long prevIndex)
  55. {
  56.     gxPoint    newPt[] = {1L, 1L, ff(0), ff(0)};
  57.     
  58.     // put the new point in newPt poly and add it to the snake
  59.     newPt[1] = *clickPt;
  60.     GXSetPolygonParts(gDragger.snake1, prevIndex + 1, 0, 
  61.                     (gxPolygons *)newPt, gxBreakNeitherEdit);
  62.     
  63.     switch(gSymmetry)
  64.     {
  65.         case p1:
  66.             p1_AddedDragPoint(prevIndex);
  67.             break;
  68.         
  69.         case pg:
  70.             pg_AddedDragPoint(prevIndex);
  71.             break;
  72.  
  73.         case pm:
  74.             break;
  75.  
  76.         case cm:
  77.             break;
  78.  
  79.         case p2:
  80.             break;
  81.         
  82.         default:
  83.             break;
  84.     }
  85.     return(prevIndex + 1);
  86. }
  87.  
  88. // Removes a point
  89. Boolean RemoveEdgePoint(long index)
  90. {
  91.     Boolean rslt = false;
  92.     
  93.     // If there are only 2 points, or if constraints are active and 
  94.     // it's a constrained point, then don't remove it
  95.     if( (GXCountShapePoints(gDragger.snake1, 0) < 3) || IsConstrainedPoint(index) ||
  96.         index == 1 )  // BUG: if index is one, GXSetPolygonParts deletes the entire contour
  97.         SysBeep(10);
  98.     else    // Remove the point
  99.     {
  100.         long    geo[25];
  101.         
  102.         GXSetPolygonParts(gDragger.snake1, index, 1, gxSetToNil, gxBreakNeitherEdit);
  103.         
  104.         switch(gSymmetry)
  105.         {
  106.             case p1:
  107.                 p1_RemovedDragPoint(index);
  108.                 break;
  109.             
  110.             case pg:
  111.                 pg_RemovedDragPoint(index);
  112.                 break;
  113.     
  114.             case pm:
  115.                 break;
  116.     
  117.             case cm:
  118.                 break;
  119.     
  120.             case p2:
  121.                 break;
  122.             
  123.             default:
  124.                 break;
  125.         }
  126.         rslt = true;
  127.     }
  128.     return rslt;
  129. }
  130.  
  131. Boolean IsConstrainedPoint(long ptIndex)
  132. {
  133.     Boolean    isConstrained = false;
  134.     
  135.     if(gKeepClosed)
  136.     {
  137.         switch(gSymmetry)
  138.         {
  139.             case p1:
  140.                 isConstrained = p1_IsVectorPoint(ptIndex);
  141.                 break;
  142.             
  143.             case pg:
  144.                 isConstrained = pg_IsVectorPoint(ptIndex);
  145.                 break;
  146.     
  147.             case pm:
  148.                 break;
  149.     
  150.             case cm:
  151.                 break;
  152.     
  153.             case p2:
  154.                 break;
  155.             
  156.             default:
  157.                 break;
  158.         }
  159.     }
  160.     return isConstrained;
  161. }
  162.  
  163. // returns true if something changed: the shell will update the window
  164. Boolean TileClick(gxPoint *clickPt, short optDown)
  165. {
  166.     gxHitTestInfo    hitStats;
  167.     gxTransform    tileXForm;
  168.     long        dragPtIndex = -1;
  169.     gxShape        dragShape;
  170.     
  171.     // Check for a dragger hit
  172.     tileXForm = GXGetShapeTransform(gDragger.snake1);
  173.     GXIgnoreGraphicsNotice(attributes_already_set);
  174.     GXSetTransformHitTest(tileXForm, gxGeometryPart, kHitTolerance);
  175.     GXPopGraphicsNotice();
  176.     
  177.     // If snake was hit, do further tests to find out what
  178.     if(GXHitTestShape(gDragger.snake1, clickPt, &hitStats))
  179.     {
  180.         // check for hit on a control point
  181.         GXSetTransformHitTest(tileXForm, gxCornerPointPart, kHitTolerance);
  182.         if(GXHitTestShape(gDragger.snake1, clickPt, &hitStats))
  183.         {
  184.             // if the option key is down, remove the point
  185.             // and change the pattern
  186.             if(optDown)
  187.             {
  188.                 if(RemoveEdgePoint(hitStats.index))
  189.                     RemakeTile();
  190.             }
  191.             
  192.             // else drag the point if it's not constrained
  193.             else
  194.             {
  195.                 if(IsConstrainedPoint(hitStats.index))
  196.                     SysBeep(10);
  197.                 else
  198.                 {
  199.                     dragShape = gDragger.snake1;
  200.                     dragPtIndex = hitStats.index;
  201.                 }
  202.             }
  203.         }
  204.         else    // Not a control point, prob'ly an edge
  205.         {
  206.             // check for hit on an edge: if so need to add a point
  207.             GXSetTransformHitTest(tileXForm, gxEdgePart, kHitTolerance);
  208.             if(GXHitTestShape(gDragger.snake1, clickPt, &hitStats))
  209.             {
  210.                 dragShape = gDragger.snake1;
  211.                 dragPtIndex = AddEdgePoint(clickPt, hitStats.index);
  212.             }
  213.         }
  214.         
  215.         // If a draggable hit, drag it
  216.         if(dragPtIndex > 0)
  217.             TrackDraggerPoint(dragPtIndex, clickPt);
  218.         return true;
  219.     }
  220.     
  221.     // Not a dragger hit, try the op shapes
  222.     return OpHit(clickPt);
  223. }
  224.  
  225. void TrackDraggerPoint(long dragPtIndex, gxPoint *startPt)
  226. {
  227.     gxPoint        pt, lastPt = *startPt;
  228.     
  229.     // Get current mouse
  230.     GXGetViewPortMouse(gViewPort, &pt);
  231.     
  232.     // Follow the drag around
  233.     while(StillDown())
  234.     {
  235.         GXGetViewPortMouse(gViewPort, &pt);
  236.         if(pt.x != lastPt.x || pt.y != lastPt.y)
  237.         {
  238.             // Erase
  239.             if(!gContRedraw)
  240.                 EraseDraggable();
  241.             
  242.             // Set new point
  243.             GXSetShapePoints(gDragger.snake1, dragPtIndex, 1, &pt);
  244.             
  245.             if(gContRedraw)
  246.             {
  247.                 // Reset pattern and draw it right now
  248.                 RemakeTile();
  249.                   GXDrawShape(gOffScreen.draw);
  250.             }
  251.               else
  252.               {
  253.                   // Just draw the dragger
  254.                   DrawDraggable();
  255.               }
  256.           }
  257.           lastPt = pt;
  258.     }
  259.  
  260.     // Update pattern if we haven't yet
  261.      if(!gContRedraw)
  262.         RemakeTile();
  263. }    
  264.  
  265. // returns true if something was hit so the shell will update the window
  266. Boolean OpHit(gxPoint *clickPt)
  267. {
  268.     Boolean goodHit = false;
  269.     
  270.     switch(gSymmetry)
  271.     {
  272.         case p1:
  273.             goodHit =  p1_OpShapeHit(clickPt);
  274.             break;
  275.         
  276.         case pg:
  277.             goodHit =  pg_OpShapeHit(clickPt);
  278.             break;
  279.  
  280.         case pm:
  281.             goodHit =  pm_OpShapeHit(clickPt);
  282.             break;
  283.  
  284.         case cm:
  285.             goodHit =  cm_OpShapeHit(clickPt);
  286.             break;
  287.  
  288.         case p2:
  289.             goodHit =  p2_OpShapeHit(clickPt);
  290.             break;
  291.         
  292.         default:
  293.             goodHit = false;
  294.             break;
  295.     }
  296.     return goodHit;
  297. }
  298.  
  299. // Set up the default OpShapes and dragger for the symmetry
  300. void DefaultTileAndPattern()
  301. {
  302.     RemakeOpShapes(true, gSymmetry);
  303.     
  304.     switch(gSymmetry)
  305.     {
  306.         case p1:
  307.             p1_SetDefaultDragger(gDragger.snake1);
  308.             p1_ChangeLattice();
  309.             break;
  310.  
  311.         case pg:
  312.             pg_SetDefaultDragger(gDragger.snake1);
  313.             pg_ChangeLattice();
  314.             break;
  315.         
  316.         case pm:
  317.             pm_SetDefaultDragger(gDragger.snake1);
  318.             pm_ChangeLattice();
  319.             break;
  320.  
  321.         case cm:
  322.             cm_SetDefaultDragger(gDragger.snake1);
  323.             cm_ChangeLattice();
  324.             break;
  325.  
  326.         case p2:
  327.             p2_SetDefaultDragger(gDragger.snake1);
  328.             p2_ChangeLattice();
  329.             break;
  330.  
  331.         default:
  332.             break;
  333.     }
  334.     if(gKeepClosed)
  335.         AttachConstraints();
  336. }                    
  337.  
  338. void AttachConstraints(void)
  339. {
  340.     // Just call the right routine to do the work
  341.     switch(gSymmetry)
  342.     {
  343.         case p1:
  344.             p1_AttachConstraints();
  345.             break;
  346.             
  347.          case pg:
  348.             pg_AttachConstraints();
  349.             break;
  350.             
  351.          case pm:
  352.             break;
  353.             
  354.         case cm:
  355.             break;
  356.         
  357.         case p2:
  358.             break;
  359.  
  360.         default:
  361.             break;
  362.     }
  363. }
  364.  
  365. // Called either to set the default shapes when resetting the tile, or when 
  366. // the symmetry has changed, to convert one lattice type to another.
  367. // Currently always uses defaults.
  368. void RemakeOpShapes(Boolean useDefaults, long newSymmetry)
  369. {
  370.     // Kill old shapes
  371.     DisposeOpShapes();
  372.     
  373.     // Make the right new ones
  374.     switch(newSymmetry)
  375.     {
  376.         case p1:    // two translate shapes
  377.             p1_RemakeOpShapes(useDefaults);
  378.             break;
  379.             
  380.          case pg:    // two glide lines
  381.             pg_RemakeOpShapes(useDefaults);
  382.             break;
  383.             
  384.          case pm:    // two mirror lines
  385.             pm_RemakeOpShapes(useDefaults);
  386.             break;
  387.             
  388.         case cm:    // a mirror and a glide
  389.             cm_RemakeOpShapes(useDefaults);
  390.             break;
  391.         
  392.         case p2:    // 3 ovals
  393.             p2_RemakeOpShapes(useDefaults);
  394.             break;
  395.  
  396.         default:
  397.             break;
  398.     }
  399. }
  400.     
  401. // Reset the tile shape according to the dragger
  402. void RemakeTile(void)
  403. {
  404.     // Copy geometry into tile to start
  405.     GXSetShapeGeometry(gTileShape, gDragger.snake1);
  406.     
  407.     // Repeat the geometry as needed for the symmetry
  408.     switch(gSymmetry)
  409.     {
  410.         case p1:    // No repeats
  411.             break;
  412.         
  413.         case pg:    // Glide reflect
  414.             pg_BuildCellShape(gDragger.snake1);
  415.             break;
  416.         
  417.         case pm:
  418.             pm_BuildCellShape(gDragger.snake1);
  419.             break;
  420.         
  421.         case cm:
  422.             cm_BuildCellShape(gDragger.snake1);
  423.             break;
  424.         
  425.         case p2:
  426.             p2_BuildCellShape(gDragger.snake1);
  427.             break;
  428.         
  429.         default:
  430.             SysBeep(10);
  431.             break;
  432.     }
  433.     
  434.     // Set the new pattern
  435.     GXIgnoreGraphicsNotice(pattern_already_set);
  436.     GXSetShapePattern(gGridShape, &gPattern);
  437.     GXPopGraphicsNotice();
  438.     
  439.     // Draw it offscreen
  440.     DrawOff();
  441. } // RemakeTile
  442.  
  443. // Change op shapes and dragger as necessary to fit new symmetry
  444. void ChangeSymmetry(long oldSym, long newSym)
  445. {
  446.     RemakeOpShapes(false, newSym);
  447.     gSymmetry = newSym;
  448.     switch(gSymmetry)
  449.     {
  450.         case p1:
  451.             p1_ChangeLattice();
  452.             break;
  453.  
  454.         case pg:
  455.             pg_ChangeLattice();
  456.             break;
  457.         
  458.         case pm:
  459.             pm_ChangeLattice();
  460.             break;
  461.  
  462.         case cm:
  463.             cm_ChangeLattice();
  464.             break;
  465.  
  466.         case p2:
  467.             p2_ChangeLattice();
  468.             break;
  469.  
  470.         default:
  471.             break;
  472.     }
  473.     if(gKeepClosed)
  474.         AttachConstraints();
  475. }
  476.                     
  477.  
  478.  
  479. //-------------------------------------------------------------
  480. //    Drawing routines    
  481.  
  482. // Draws everything
  483. void TileUpdate(void)
  484. {
  485.     // Transfer grid from offscreen
  486.     GXDrawShape(gOffScreen.draw);
  487.  
  488.      // Draw the ops shapes
  489.      DrawOpShapes();
  490.  
  491.      // Draw the draggable bit
  492.      DrawDraggable();
  493. }
  494.  
  495. void DrawOff(void)
  496. {
  497.     GXDrawShape(gBGShape);
  498.       GXDrawShape(gGridShape);
  499. }
  500.  
  501. void OffToScreen(void)
  502. {
  503.     GXDrawShape(gOffScreen.draw);
  504. }
  505.           
  506. void DrawDraggable(void)
  507. {
  508.      GXDrawShape(gDragger.snake1);
  509. }
  510.  
  511. void EraseDraggable(void)
  512. {
  513.     EraseAShape(gDragger.snake1);
  514. }
  515.  
  516. void DrawOpShapes(void)
  517. {
  518.     short    cnt = kNumOpShapes;
  519.     
  520.     while(--cnt >= 0)
  521.         if(gOpShapes[cnt] != nil)
  522.             GXDrawShape(gOpShapes[cnt]);
  523. }
  524.  
  525. void EraseXShape(gxShape theShape);
  526.  
  527. // Erases by drawing it in the BG color
  528. void EraseAShape(gxShape theShape)
  529. {
  530.     commonColor    savedColor;
  531.     
  532.     GXIgnoreGraphicsNotice(color_already_set);
  533.     
  534.     savedColor = GetShapeCommonColor(theShape);
  535.     SetShapeCommonColor(theShape, kBGColor);
  536.     GXDrawShape(theShape);
  537.     SetShapeCommonColor(theShape, savedColor);
  538.  
  539.     GXPopGraphicsNotice();
  540. }
  541.  
  542. // Erases by copying from the offscreen
  543. void EraseXShape(gxShape theShape)
  544. {
  545.     gxShape        savedClip, tempShape;
  546.     gxRectangle    shapeBounds;
  547.     
  548.      tempShape = GXCopyToShape(nil, theShape);
  549.     GXPrimitiveShape(tempShape);
  550.     GXGetShapeBounds(tempShape, 0, &shapeBounds);
  551.     GXDisposeShape(tempShape);
  552.     tempShape = GXNewRectangle(&shapeBounds);
  553.     savedClip = GXGetShapeClip(gOffScreen.draw);
  554.     GXSetShapeClip(gOffScreen.draw, tempShape);
  555.     GXDisposeShape(tempShape);
  556.     GXDrawShape(gOffScreen.draw);
  557.     GXSetShapeClip(gOffScreen.draw, savedClip);
  558.     GXDisposeShape(savedClip);
  559. }
  560.  
  561. void DisposeDragger(void)
  562. {
  563.     GXDisposeShape(gDragger.snake1);
  564. }
  565.  
  566. void DisposeOpShapes(void)
  567. {
  568.     short    cnt = kNumOpShapes;
  569.     
  570.     while(--cnt >= 0)
  571.         if(gOpShapes[cnt] != nil)
  572.         {
  573.             GXDisposeShape(gOpShapes[cnt]);
  574.             gOpShapes[cnt] = nil;
  575.         }
  576. }
  577.  
  578. //-------------------------------------------------------------
  579. //    From Luke    
  580.  
  581. gxShape  GetWindowBoundsShape(WindowPtr wind)
  582. {
  583.     Rect            theRect;
  584.     Point            QDtopLeft;
  585.     Point            QDbotRight;
  586.     gxPoint            QD2topLeft;
  587.     gxPoint            QD2botRight;
  588.     gxRectangle        theQD2Rect;
  589.     
  590.     /**  The QuickDraw rect and points which represent the portRect of the window.  **/
  591.     theRect = wind->portRect;
  592.     QDtopLeft.h = theRect.left;
  593.     QDtopLeft.v = theRect.top;
  594.     QDbotRight.h = theRect.right;
  595.     QDbotRight.v = theRect.bottom;
  596.     
  597.     /**  Convert the global Quickdraw coordinates to local fixed coordinates.  **/
  598.     GXConvertQDPoint(&QDtopLeft, 0, &QD2topLeft);
  599.     GXConvertQDPoint(&QDbotRight, 0, &QD2botRight);
  600.  
  601.     /**  Setup the dimensions for "gBGShape" **/ 
  602.     theQD2Rect.top = QD2topLeft.y;
  603.     theQD2Rect.left = QD2topLeft.x;
  604.     theQD2Rect.bottom = QD2botRight.y;
  605.     theQD2Rect.right = QD2botRight.x;
  606.     
  607.     return (GXNewRectangle(&theQD2Rect));
  608. }
  609.  
  610. Boolean ChangeWindowSize(WindowPtr wind, short hSize, short vSize)
  611. {
  612.     gxBitmap        offMap;
  613.     gxShape        offBits;
  614.     gxRectangle    windRect;
  615.     
  616.     // Try to remake the off-screen bitmap. !!! I'm sure there's a better way to do this,
  617.     // just resizing the appropriate bitmap shape, whichever one it is.
  618.     offMap.image = nil;
  619.     offMap.width = hSize;
  620.     offMap.height = vSize;
  621.     offMap.rowBytes = 0;
  622.     offMap.pixelSize = 8;
  623.     offMap.space = gxIndexedSpace;
  624.     offMap.set = gColors;
  625.     offMap.profile = nil;
  626.     offBits = GXNewBitmap(&offMap, &gOrigin);
  627.     if(offBits <= (gxShape)nil)
  628.         return false;
  629.     
  630.     // Kill old one and make new one
  631.     DisposeOffscreen(&gOffScreen);
  632.     CreateOffscreen(&gOffScreen, offBits);
  633.     GXDisposeShape(offBits);
  634.     
  635.     // Size the window
  636.     SizeWindow(wind, hSize, vSize, true);
  637.     ClipRect(&wind->portRect);
  638.     
  639.     // Update other 2 rect shapes
  640.     ShortRectToFixed(&wind->portRect, &windRect);
  641.     GXSetRectangle(gBGShape, &windRect);
  642.     GXSetRectangle(gGridShape, &windRect);
  643.     
  644.     // Set them to draw in new offscreen
  645.     GXSetShapeTransform(gBGShape, gOffScreen.xform);
  646.     GXSetShapeTransform(gGridShape, gOffScreen.xform);
  647.     
  648.     // Update the offscreen
  649.     DrawOff();
  650.     
  651.     return true;
  652. }
  653.  
  654. void SetLinePoints(gxShape theLine, gxPoint *start, gxPoint *end)
  655. {
  656.     gxLine    newGeo;
  657.     
  658.     newGeo.first = *start;
  659.     newGeo.last = *end;
  660.     GXSetLine(theLine, &newGeo);
  661. }